#include "Dri_MQTT.h"
#include "Com_Debug.h"
#include "cJSON.h"

static const char *TAG = "mqttwss_example";

#if CONFIG_BROKER_CERTIFICATE_OVERRIDDEN == 1
static const uint8_t mqtt_eclipseprojects_io_pem_start[] =
    "-----BEGIN CERTIFICATE-----\n" CONFIG_BROKER_CERTIFICATE_OVERRIDE "\n-----END CERTIFICATE-----";
#else
extern const uint8_t mqtt_eclipseprojects_io_pem_start[] asm("_binary_mqtt_eclipseprojects_io_pem_start");
#endif
extern const uint8_t mqtt_eclipseprojects_io_pem_end[] asm("_binary_mqtt_eclipseprojects_io_pem_end");

// main任务句柄
extern TaskHandle_t main_task_handle;

// 解析JSON数据
static void Dri_MQTT_parse_json_data(esp_mqtt_event_handle_t client) {

  // 取出事件中的数据 {"cmd":"on","type":"audio","dir":"client2esp"}
  char *data = client->data;
   MY_LOGE("解析JSON数据:data      %s", data);
  // 解析JSON数据
  cJSON *jsonObj = cJSON_Parse(data);

  // 从JSON中取出单个值
  cJSON *cmdJson = cJSON_GetObjectItem(jsonObj, "cmd");   // {"cmd":"on"}
  char *cmdStr = cJSON_GetStringValue(cmdJson);           // "on"
  cJSON *typeJson = cJSON_GetObjectItem(jsonObj, "type"); // {"type":"audio"}
  char *typeStr = cJSON_GetStringValue(typeJson);         // "audio"
  cJSON *dirJson = cJSON_GetObjectItem(jsonObj, "dir");   // {"dir":"client2esp"}
  char *dirStr = cJSON_GetStringValue(dirJson);           // "client2esp"

  // 根据具体数据给主任务发送通知
  uint32_t action = ACTION_AUDIO_VIDEO_NO;

  MY_LOGE("解析JSON数据:typeStr     %s", typeStr);
  if (strcmp(typeStr, "audio") == 0) {
    if (strcmp(dirStr, "client2esp") == 0) {
      if (strcmp(cmdStr, "on") == 0) {
        action = ACTION_AUDIO_CLIENT2ESP_ON;
      } else if (strcmp(cmdStr, "off") == 0) {
        action = ACTION_AUDIO_CLIENT2ESP_OFF;
      }
    } else if (strcmp(dirStr, "esp2client") == 0) {
      if (strcmp(cmdStr, "on") == 0) {
        action = ACTION_AUDIO_ESP2CLIENT_ON;
      } else if (strcmp(cmdStr, "off") == 0) {
        action = ACTION_AUDIO_ESP2CLIENT_OFF;
      }
    }
  } else if (strcmp(typeStr, "video") == 0) {
    if (strcmp(cmdStr, "on") == 0) {
      action = ACTION_VIDIO_ESP2CLIENT_ON;
    } else if (strcmp(cmdStr, "off") == 0) {
      action = ACTION_VIDIO_ESP2CLIENT_OFF;
    }
  }
  // 给主任务发送通知
  xTaskNotify(main_task_handle, action, eSetValueWithOverwrite);

  // 清除缓存
  cJSON_Delete(jsonObj);
}

static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) {
  esp_mqtt_client_handle_t client = event->client;
  int msg_id;
  // your_context_t *context = event->context;
  switch (event->event_id) {
    // 当 MQTT 客户端成功连接到代理服务器时触发
    case MQTT_EVENT_CONNECTED:
      printf("MQTT连接成功,订阅'teacher/cmd'主题\r\n");
      msg_id = esp_mqtt_client_subscribe(client, "teacher/cmd_yhf", 0);
      ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);

      break;

    // 当 MQTT 客户端与代理服务器断开连接时触发
    case MQTT_EVENT_DISCONNECTED:
      ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
      MY_LOGE("当 MQTT 客户端与代理服务器断开连接时触发");
      break;

    // 当 MQTT 客户端成功订阅主题时触发
    case MQTT_EVENT_SUBSCRIBED:
      ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
      msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
      ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
      MY_LOGE("当 MQTT 客户端成功订阅主题时触发");
      break;

    // 当 MQTT 客户端成功取消订阅主题时触发
    case MQTT_EVENT_UNSUBSCRIBED:
      ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
      MY_LOGE("当 MQTT 客户端成功取消订阅主题时触发");
      break;

    // 当 MQTT 客户端成功发布消息时触发
    case MQTT_EVENT_PUBLISHED:
      ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
      MY_LOGE("当 MQTT 客户端成功发布消息时触发");
      break;

    // 当 MQTT 客户端接收到消息时触发
    case MQTT_EVENT_DATA:
      ESP_LOGI(TAG, "MQTT_EVENT_DATA");
      MY_LOGE("当 MQTT 客户端接收到消息时触发");
      printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
      printf("DATA=%.*s\r\n", event->data_len, event->data);
      Dri_MQTT_parse_json_data(event);
      break;

    // 当 MQTT 客户端发生错误时触发
    case MQTT_EVENT_ERROR:
      ESP_LOGI(TAG, "当 MQTT 客户端发生错误时触发");
      break;

    default:
      ESP_LOGI(TAG, "Other event id:%d", event->event_id);
      break;
  }
  return ESP_OK;
}

static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) {
  /* The argument passed to esp_mqtt_client_register_event can de accessed as handler_args*/
  ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32, base, event_id);
  mqtt_event_handler_cb(event_data);
}

static void mqtt_app_start(void) {
  const esp_mqtt_client_config_t mqtt_cfg = {
      .broker.address.uri = "wss://broker.emqx.io:8084/mqtt", // 代理服务器的地址和端口
      //.broker.verification.certificate = NULL,
      .broker.verification.certificate = (const char *)mqtt_eclipseprojects_io_pem_start,
      //  .credentials.username = "111",
      //  .credentials.authentication.password = "111",
  };

  MY_LOGE("mqtt_配置完成");

  ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
  // 根据配置初始化 MQTT 客户端，并获取客户端句柄
  esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
  /*
   * 为 MQTT 客户端注册事件处理函数，当发生任何 MQTT 事件时，都会调用 mqtt_event_handler 函数。
   * 最后一个参数为 NULL，表示不传递额外的数据给事件处理函数。
   */
  esp_err_t err = esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
  MY_LOGE("客户端注册事件处理函数，当发生任何 %d", err);
  err = esp_mqtt_client_start(client);
  MY_LOGE("启动 MQTT 客户端  %d", err);
}

/**
 * @brief 初始化
 *
 */
void Dri_MQTT_Init(void) {
  // 不需要这些初始化,在wifi的时候已经初始化
  // ESP_ERROR_CHECK(nvs_flash_init());
  // ESP_ERROR_CHECK(esp_netif_init());
  // ESP_ERROR_CHECK(esp_event_loop_create_default());

  // 不要启动wifi
  // ESP_ERROR_CHECK(example_connect());

  mqtt_app_start();
}
